Product update
Business scenario
When a merchant updates a product in their integrated system — changing its name, price, SKU, or inventory tracking setting — that change must be reflected in Qoyod for the two systems to remain aligned. If Qoyod holds a stale version of the product, invoices referencing it carry incorrect prices, the chart of accounts records costs against outdated values, and any reporting that draws on product data diverges from the merchant's actual catalog.
This use case covers the integrated system to Qoyod direction: your integration detects
that a product has been modified in the integrated system, then sends a request to Qoyod to
apply those changes to the matching product record. The Qoyod record is identified by the
numeric product id that your integration stored when the product was first created (see
New product creation).
A successful update leaves both systems holding the same current attribute values for the product. A missed or failed update leaves Qoyod out of date until the next successful synchronization. Persistent drift between systems requires a sync reconciliation pass to identify and resolve conflicts.
When to use this
Use this when:
- A product already exists in Qoyod (you have its numeric Qoyod product
idstored) and one or more of its attributes have changed in the integrated system. - You need to change a product's name, SKU, price, inventory tracking setting, category, or tax association.
- The change originated in the integrated system and Qoyod should receive it — this is an integrated system to Qoyod flow.
Do not use this when:
- The product does not yet exist in Qoyod — create it first using New product creation (UC-01).
- You need to adjust stock quantities — stock is managed through inventory adjustments, not through the product update endpoint.
- You need to change the product's
typeclassification —typecannot be changed after creation. See Edge cases and gotchas for details. - You need to update many products at once as part of a bulk migration — see Initial product import for batch considerations.
Prerequisites
- A valid OAuth 2.0 access token for the Qoyod account you are integrating with.
- The Qoyod product
idfor the product you intend to update. This is the integer ID returned in the201 Createdresponse when the product was first created and stored by your integration. If you do not have this ID, follow New product creation first — there is no reliable way to update a product without its Qoyod ID. - If your update sets or changes
category_id, the target category must already exist in Qoyod. Retrieve its integeridfrom the categories endpoint before sending the update request. - If your update sets or changes
tax_id, the target tax record must already exist in Qoyod. Retrieve its integeridbefore sending the update request.
Sequence diagram
Step-by-step
1. Confirm the stored Qoyod product ID
Before sending an update, verify that your integration has a Qoyod product id stored
for the item. This ID was returned in the 201 Created response when the product was
first created and must be persisted in your integrated system. If no ID is stored, the
product does not yet exist in Qoyod — follow New product creation
instead.
2. Build the request body with only the changed fields
Wrap the fields you want to update inside a product object. You do not need to send
the full product record — only include the fields that have changed. Omitting a field
does not clear it; Qoyod leaves unchanged fields at their current values.
{
"product": {
"selling_price": 30.00,
"sku": "MUG-BLUE-002"
}
}
If you are updating the product name, send the appropriate name field. Both the English and Arabic name fields accept aliases — use whichever your integration normalizes to.
{
"product": {
"en_name": "Blue Ceramic Mug — Large",
"name": "كوب سيراميك أزرق - كبير"
}
}
3. Send the PUT request
Send a PUT request to https://api.qoyod.com/2.0/products/{id}, replacing {id} with
the stored Qoyod product id. Include the Authorization header with your access token.
curl -X PUT https://api.qoyod.com/2.0/products/{product_id} \
-H "Authorization: Bearer {access_token}" \
-H "Content-Type: application/json" \
-d '{
"product": {
"selling_price": 30.00,
"sku": "MUG-BLUE-002"
}
}'
4. Handle the 200 OK response
A successful update returns 200 OK with the full updated product record nested under a
product key. This is the complete current state of the product in Qoyod — not a partial
echo of what you sent.
{
"product": {
"id": 1087,
"name_ar": "كوب سيراميك أزرق",
"name_en": "Blue Ceramic Mug",
"type": "Product",
"sku": "MUG-BLUE-002",
"selling_price": 30.0,
"buying_price": 12.0,
"is_sold": true,
"is_bought": true,
"track_quantity": 1,
"category_id": 42,
"updated_at": "2026-05-18T11:45:00.000Z"
}
}
Confirm that the fields you sent appear with the expected values in the response. If a field does not reflect your update, check whether the field name you used is a supported alias — the response always returns canonical field names regardless of the alias used in the request.
5. Verify the update
After confirming the 200 OK response, retrieve the product via
GET /2.0/products/{id} to confirm the record reflects the updated values independently
of the update response. See the Verification section below.
Field mapping
The table below maps common integrated system concepts to the corresponding Qoyod fields
for the product update request. All field names match the PUT /2.0/products/{id} request
body exactly. Only send the fields that have changed — the endpoint applies a partial
update; untouched fields retain their current values.
| Integrated system concept | Qoyod field | Required | Notes |
|---|---|---|---|
| Product name (English) | en_name | No | Also accepted as name_en. Only send if the name has changed. |
| Product name (Arabic) | name | No | Also accepted as name_ar or ar_name. Only send if the name has changed. |
| SKU | sku | No | Pass through from the integrated system. |
| Selling price | selling_price | No | Numeric. Updates the selling price. If is_sold was previously false, Qoyod sets it to true when this field is present. |
| Buying price | buying_price | No | Numeric. Updates the buying price. If is_bought was previously false, Qoyod sets it to true when this field is present. |
| Inventory tracking enabled | track_quantity | No | 0 = untracked, 1 = tracked. Can be changed on update. |
| Category | category_id | No | Must reference an existing Qoyod category ID. |
| Tax | tax_id | No | Must reference an existing Qoyod tax ID. |
For the complete list of fields accepted by this endpoint, see the products reference.
Verification
After the PUT request returns 200 OK, retrieve the product to confirm the update was
applied correctly.
curl -X GET https://api.qoyod.com/2.0/products/{product_id} \
-H "Authorization: Bearer {access_token}"
A successful retrieval returns 200 OK with a product object. Confirm:
- The
idfield matches the product ID you updated. - Each field you changed in the PUT request reflects the new value.
updated_athas advanced to a timestamp after your PUT request.- Fields you did not send in the PUT request retain their previous values — this confirms the partial update behavior is working as expected.
If a field does not reflect the expected value, check the alias table in
New product creation — the name and en_name
fields each accept multiple aliases on input, but the response always returns the canonical
field names name_ar and name_en.
The verification step is optional but recommended during initial integration development.
Once your integration is stable and you trust the 200 OK response, the separate GET
request adds latency without additional value for most production flows.
Error scenarios
| Status code | When it occurs | What to do |
|---|---|---|
422 Unprocessable Entity | Qoyod could not apply the update due to a validation failure. The response body contains an errors object where keys are field names and values are arrays of error strings. | Read the errors object to identify which fields failed validation. Correct the field values in your request body and retry. |
422 Unprocessable Entity | The category_id or tax_id you sent does not reference an existing record in Qoyod. | Verify the referenced ID by querying the appropriate Qoyod endpoint. Ensure the category or tax record exists before sending the update. |
404 Not Found | The product ID in the request path does not match any product in Qoyod. This typically means the stored Qoyod product ID is stale, was deleted, or was copied from the wrong record. | Check your integration's stored product ID for this item. If the product was deleted from Qoyod, re-create it using New product creation and store the new ID. |
401 Unauthorized | The access token is missing, expired, or invalid. | Refresh the OAuth 2.0 access token and retry the request. |
For retry logic, exponential backoff guidance, and how to interpret the errors response
object, see error handling.